package com.example.leepong.Drawing;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;

import com.example.leepong.Game.Engine;
import com.example.leepong.Game.Engines.HumanPlayer;
import com.example.leepong.Game.Entities.Ball;
import com.example.leepong.Game.Entities.Score;
import com.example.leepong.Game.Shapes.Rectangle;
import com.example.leepong.Game.Utils.PerfsMonitor;
import com.example.leepong.Game.Utils.Stopwatch;
import com.example.leepong.GameSurface;
import com.example.leepong.Helpers.ShapesHelpers;
import com.example.leepong.R;

import java.util.ArrayList;

/**
 * Created by Ichigo on 27/02/14.
 */
public class DrawingManager {
    private GameSurface _surface;
    private BitmapDrawable _ballFuildDrawable;

    private BitmapDrawable _ballDrawable;
    private BitmapDrawable _raquetDrawable;
    private BitmapDrawable _landDrawable;
    private BitmapDrawable _arrowDrawable;

    private BitmapDrawable _federerDrawable;

    public boolean ShowShadowBalls = true;
    private int SHADOW_COUNT = 10;
    private ArrayList<RectF> _shadowBalls = new ArrayList<RectF>();
    private Paint _ballPaint = new Paint();
    private Paint _ballPaint2 = new Paint();
    private Paint _textPaint = new Paint();
    private Paint _fpsPaint = new Paint();

    public boolean ShowFps;
    public int DesiredFpsValue = 0;
    private int _currentFps;
    private int _fpsSleepPeriod = 15;
    private Stopwatch _fpsWatch = new Stopwatch();
    private int _fpsCounter;
    private Bitmap _landBitmap;
    private Bitmap _ballBitmap;
    private Bitmap _ballFluidBitmap;
    private Bitmap _racketBitmap;
    private Bitmap _arrowBitmap;
    private Bitmap _federerBitmap;

    public DrawingManager(GameSurface surface) {

        this._surface = surface;

        Resources resources = _surface.getContext().getResources();

        BitmapFactory.Options set = new BitmapFactory.Options();
        set.inScaled = false;
        set.inPreferredConfig = Bitmap.Config.RGB_565;
        _ballFuildDrawable = new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.soccerfluid, set));
        _ballDrawable = new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.soccer, set));
        _raquetDrawable = new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.racket, set));
        _landDrawable = new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.landtexture, set));
        _arrowDrawable = new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.arrowdown, set));
        _federerDrawable = new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.federer, set));

        _textPaint.setARGB(150, 255, 255, 255);
        _textPaint.setTypeface(Typeface.DEFAULT_BOLD);
        _textPaint.setTextAlign(Paint.Align.CENTER);

        _fpsPaint.setARGB(255, 40, 200, 200);
        _fpsPaint.setTextSize(40);
//        _ballPaint2.setAntiAlias(true);
//        _ballPaint2.setDither(true);
        _ballPaint2.setFilterBitmap(true);
    }

    public void Init() {
        Engine engine = this._surface.Engine;
        _textPaint.setTextSize(_surface.Engine.LeftScore.Rect.Height);

        _landBitmap = Bitmap.createScaledBitmap(_landDrawable.getBitmap(), engine.Land.Rect.Width, engine.Land.Rect.Height, true);
        _ballBitmap = Bitmap.createScaledBitmap(_ballDrawable.getBitmap(), engine.Ball.Rect.Width, engine.Ball.Rect.Height, true);
        _ballFluidBitmap = Bitmap.createScaledBitmap(_ballFuildDrawable.getBitmap(), engine.Ball.Rect.Width, engine.Ball.Rect.Height, true);
        _racketBitmap = Bitmap.createScaledBitmap(_raquetDrawable.getBitmap(), engine.TopRacket.Rect.Width, engine.TopRacket.Rect.Height, true);
        _arrowBitmap = Bitmap.createScaledBitmap(_arrowDrawable.getBitmap(), engine.TopRacket.Rect.Width, engine.TopRacket.Rect.Height, true);

        _federerBitmap = Bitmap.createScaledBitmap(_federerDrawable.getBitmap(), engine.TopRacket.Rect.Width, engine.TopRacket.Rect.Height, true);

        _fpsWatch.Restart();
    }

    public void DoDraw(final Canvas canvas) {

        PerfsMonitor.Monitor("Drawing", 300, new Runnable() {
            @Override
            public void run() {
                DrawInternal(canvas);
            }
        });
        HandleFps(canvas);
    }

    private Rectangle GetRectCentred(Rectangle original, float widthRatio, float heightRatio) {
        float newWidth = widthRatio * original.Width;
        float newHeight = heightRatio * original.Height;

        float x = original.CenterX() - newWidth / 2;
        float y = original.CenterY() - newHeight / 2;
        return new Rectangle(x, y, (int) newWidth, (int) newHeight);
    }

    private void DrawInternal(Canvas canvas) {
        Engine engine = this._surface.Engine;

        canvas.drawBitmap(_landBitmap, null, ShapesHelpers.ToRectF(engine.Land.Rect), null);
        //  canvas.drawColor(_backColor);
        //  canvas.drawColor(Color.WHITE);
        DrawScore(canvas, engine.RightScore);
        DrawScore(canvas, engine.LeftScore);

        canvas.drawBitmap(_racketBitmap, null, ShapesHelpers.ToRectF(engine.TopRacket.Rect), null);
        canvas.drawBitmap(_racketBitmap, null, ShapesHelpers.ToRectF(engine.BottomRacket.Rect), null);

        Rectangle federRect = GetRectCentred(engine.TopRacket.Rect, 0.8f, 0.8f);
        canvas.drawBitmap(_federerBitmap, null, ShapesHelpers.ToRectF(federRect), _ballPaint2);

        RectF ballrect = ShapesHelpers.ToRectF(engine.Ball.Rect);
        DrawBall(canvas, ballrect);

        DrawArrow(canvas);
    }

    private long prev;

    private void HandleFps(Canvas canvas) {

        if (!ShowFps && DesiredFpsValue == 0)
            return;

        _fpsCounter++;
        if (_fpsCounter % 100 == 0) {
            long now = _fpsWatch.getElapsedMilliseconds();
            _currentFps = (int) (100 / ((now - prev) / 1000.0));
            //  Log.d("----", "draw fps" + _currentFps);
            prev = now;


            if (DesiredFpsValue > 0) {
                double diff = _currentFps - DesiredFpsValue;
                if (diff < 0)
                    _fpsSleepPeriod = _fpsSleepPeriod <= 1 ? 1 : _fpsSleepPeriod - 1;
                else {
                    _fpsSleepPeriod++;
                }
            }
        }

        if (ShowFps)
            DrawFps(canvas, _currentFps);
    }

    private void DrawFps(Canvas canvas, int fps) {
        float x = 300;
        float y = 20;

        canvas.save();
        canvas.drawText(String.valueOf(fps), x, y, _fpsPaint);
        canvas.restore();
    }

    private void DrawScore(Canvas canvas, Score score) {

        _textPaint.setARGB(100 + score.Glow, 255, 255, 255);

        canvas.save();

        canvas.drawText(String.valueOf(score.Points), score.Rect.X, score.Rect.Y, _textPaint);
        canvas.restore();
    }

    private void DrawBall(Canvas canvas, RectF lastRec) {

        Ball ball = this._surface.Engine.Ball;

        if (ShowShadowBalls) {
            for (int i = 0; i < _shadowBalls.size(); i++) {
                int alpha = (40 / SHADOW_COUNT) * (i + 1);

                _ballPaint.setAlpha(alpha);
                RectF re = _shadowBalls.get(i);
                //canvas.Save();
                //canvas.Rotate(ball.Angle + 90, re.CenterX(), re.CenterY());
                canvas.drawBitmap(_ballBitmap, null, re, _ballPaint);
                //canvas.Restore();
            }


            if (_shadowBalls.size() == SHADOW_COUNT) {
                _shadowBalls.remove(0);

            }
            _shadowBalls.add(_shadowBalls.size(), lastRec);
        }

        Bitmap bitmap = _ballBitmap;
        if (ball.MoveStep > 3 && this._surface.Engine.IsRunning) {
            bitmap = _ballFluidBitmap;
        }
        canvas.save();
        canvas.rotate(ball.Angle + 90, ball.Rect.CenterX(), ball.Rect.CenterY());
        canvas.drawBitmap(bitmap, null, lastRec, _ballPaint2);
        canvas.restore();
    }

    private void DrawArrow(Canvas canvas) {
        Engine engine = this._surface.Engine;

        HumanPlayer player = (engine.BottomRacket.Player instanceof HumanPlayer) ? (HumanPlayer) engine.BottomRacket.Player : null;
        if (player == null)
            return;

        Rectangle r = engine.BottomRacket.Rect;
        RectF arrowrec = new RectF();
        arrowrec.top = r.Top() - r.Height;
        arrowrec.left = r.Left();
        arrowrec.right = r.Right();
        arrowrec.bottom = r.Top();

        canvas.save();
        canvas.rotate(player._tendencyAngle + 90, r.CenterX(), r.Top());
        canvas.drawBitmap(_arrowBitmap, null, arrowrec, null);
        canvas.restore();
    }
}
